 
package com.zdkj.subway.rca.service.impl;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;

import com.zdkj.subway.rca.dto.out.SwCkInternetTicketEquipmentDateExcelDTO;
import com.zdkj.subway.rca.dto.out.SwCkInternetTicketEquipmentLineExcelDTO;
import com.zdkj.subway.rca.entity.SwCkInternetTicketEquipment;
import com.zdkj.subway.rca.mapper.SwCkInternetTicketEquipmentMapper;
import com.zdkj.subway.rca.service.SwCkInternetTicketEquipmentService;
import com.zdkj.subway.rca.util.LocalDateConverter;
import com.zdkj.subway.rca.util.LocalDateTimeConverter;
import com.zdkj.subway.rca.util.excel.SwAuInternetTicketEquipmentLineExcelColumnWidthStrategy;
import com.zdkj.subway.rca.util.excel.SwAuInternetTicketEquipmentLineExcelHorizontalCellStyleStrategy;
import com.zdkj.subway.rca.util.excel.SwAuInternetTicketEquipmentLineExcelMergeStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Service;


import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;

/**
 * 互联网售票机
 *
 * @author stw
 * @date 2020-02-13 11:40:36
 */
@Service
public class SwCkInternetTicketEquipmentServiceImpl extends ServiceImpl<SwCkInternetTicketEquipmentMapper, SwCkInternetTicketEquipment> implements SwCkInternetTicketEquipmentService {
    private static final Logger log = LoggerFactory.getLogger(SwCkInternetTicketEquipmentServiceImpl.class);

    @Override
    public void exportExcelGroupLine(String startDate, String endDate,String lineCodes,HttpServletResponse response){
        List<String> listLineCodes = new ArrayList<>();
        if(StringUtils.isNotEmpty(lineCodes)) {
            String[] arr = lineCodes.split(",");
            Collections.addAll(listLineCodes, arr);
        }

        List<SwCkInternetTicketEquipmentLineExcelDTO> records  = listGroupLine(startDate,endDate,listLineCodes);
        List<SwCkInternetTicketEquipmentLineExcelDTO> stationList = getStationList(records);
        List<BigDecimal> unitPriceList = getUnitPriceList(records);

        // 表格数据
        List<List<Object>> dataList = getDataList(records,stationList,unitPriceList);

        try {response.reset(); // 非常重要
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            final String fileName = URLEncoder.encode("互联网售票机(分线路)数据", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + System.currentTimeMillis() + ".xlsx");
            //自定义 合并行 列
            int[] mergeColumeIndex = {0};
            int mergeRowIndex = 3;
            // 自定义合并策略，
            SwAuInternetTicketEquipmentLineExcelMergeStrategy mergeStrategy = new SwAuInternetTicketEquipmentLineExcelMergeStrategy(mergeRowIndex, mergeColumeIndex);

            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
                    // 设置统一的表头、表内容样式
                    .registerWriteHandler(SwAuInternetTicketEquipmentLineExcelHorizontalCellStyleStrategy.style())
                    // 设置表头，表内容的行高

                    .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 20, (short) 20))
                    .build();

            WriteSheet writeSheet = EasyExcel.writerSheet(0, "互联网售票机(分线路)数据")
                    .registerWriteHandler(new SwAuInternetTicketEquipmentLineExcelColumnWidthStrategy())
                    .registerWriteHandler(mergeStrategy)
                    // 自定义多级复杂表头
                    .head(getHead(startDate,endDate,unitPriceList))
                    .build();

            excelWriter.write(dataList, writeSheet);
            excelWriter.finish();

        } catch (IOException e) {
            e.printStackTrace();
            log.error("导出互联网售票机(分线路)数据错误");
        }
    }
    private List<SwCkInternetTicketEquipmentLineExcelDTO> listGroupLine(String startDate, String endDate, List<String> listLineCodes) {
        return this.baseMapper.listGroupLine(startDate,endDate,listLineCodes);
    }

    /**
     * 得到表头
     * @param
     * @return
     */
    private static List<List<String>> getHead(String startDate, String endDate,List<BigDecimal> unitPriceList) {

        if (startDate == null){
            startDate = "";
        }
        if (endDate == null){
            endDate = "";
        }

        List<List<String>> headTitles = Lists.newArrayList();

        String settlementTime = "清算日期:", settlementTimeValue = startDate + "-" + endDate,lineInfo = "线路",stationInfo = "车站",saleNumberInfo = "发售数量/张",totalSaleAmountInfo = "小计金额/元",empty = "";

        //第一列，1/2/3行
        headTitles.add( Lists.newArrayList(settlementTime,lineInfo) );

        //第二列，1/2/3行
        headTitles.add( Lists.newArrayList(settlementTimeValue,stationInfo ) );
        //第三列，1/2/3行
        headTitles.add( Lists.newArrayList(settlementTimeValue,unitPriceList.get(0) +"元", saleNumberInfo));

        //第四列，1/2/3行
        headTitles.add( Lists.newArrayList(empty,unitPriceList.get(0) +"元", totalSaleAmountInfo));

        for (int i = 1;i <  unitPriceList.size(); i++) {
            headTitles.add( Lists.newArrayList(empty,unitPriceList.get(i)  + "元", saleNumberInfo) );
            headTitles.add( Lists.newArrayList(empty,unitPriceList.get(i)  + "元", totalSaleAmountInfo));
        }

        headTitles.add( Lists.newArrayList(empty,"合计", saleNumberInfo) );
        headTitles.add( Lists.newArrayList(empty,"合计", totalSaleAmountInfo));

        headTitles.add( Lists.newArrayList(empty,"备注"));
        return headTitles;

    }

    /**
     * 得到站点列表
     * @param records
     * @return
     */
    private List<SwCkInternetTicketEquipmentLineExcelDTO> getStationList(List<SwCkInternetTicketEquipmentLineExcelDTO> records) {

        Set<SwCkInternetTicketEquipmentLineExcelDTO> stationSet = new LinkedHashSet<>();
        for (SwCkInternetTicketEquipmentLineExcelDTO dto : records){
            SwCkInternetTicketEquipmentLineExcelDTO swCkInternetTicketEquipmentLineExcelDTO = new SwCkInternetTicketEquipmentLineExcelDTO();
            swCkInternetTicketEquipmentLineExcelDTO.setLineName(dto.getLineName());
            swCkInternetTicketEquipmentLineExcelDTO.setStationName(dto.getStationName());
            stationSet.add(swCkInternetTicketEquipmentLineExcelDTO);
        }
        List<SwCkInternetTicketEquipmentLineExcelDTO> stationList = new ArrayList<>(stationSet);
        return stationList;
    }

    /**
     * 得到单价列表
     * @param records
     * @return
     */
    private List<BigDecimal> getUnitPriceList(List<SwCkInternetTicketEquipmentLineExcelDTO> records) {

        Set<BigDecimal> unitPriceSet = new LinkedHashSet<>();
        for (SwCkInternetTicketEquipmentLineExcelDTO dto : records){
            unitPriceSet.add(dto.getUnitPrice());
        }

        List<BigDecimal> unitPriceList = new ArrayList<>(unitPriceSet);
        Collections.sort(unitPriceList);
        return unitPriceList;
    }

    /**
     * getDataList
     * @param records
     * @return
     */
    private List<List<Object>> getDataList(List<SwCkInternetTicketEquipmentLineExcelDTO> records, List<SwCkInternetTicketEquipmentLineExcelDTO> stationList, List<BigDecimal> unitPriceList) {
        List<List<Object>> dataList = new ArrayList<>();

        //处理数据行
        for (SwCkInternetTicketEquipmentLineExcelDTO station : stationList){
            List<Object> list = new ArrayList<>();
            list.add(station.getLineName());
            list.add(station.getStationName());

            Integer saleNumberSum = 0;
            BigDecimal totalSaleAmountSum = new BigDecimal(0.0);

            for (BigDecimal unitPrice : unitPriceList) {
                Integer saleNumber = 0;
                BigDecimal totalSaleAmount = new BigDecimal(0.0);
                for(SwCkInternetTicketEquipmentLineExcelDTO dto : records){
                    if(unitPrice.equals(dto.getUnitPrice()) && station.getStationName().equals(dto.getStationName()) && station.getLineName().equals(dto.getLineName())){
                        saleNumber = dto.getSaleNumber();
                        totalSaleAmount = dto.getTotalSaleAmount();
                        saleNumberSum += saleNumber;
                        totalSaleAmountSum = totalSaleAmountSum.add(totalSaleAmount);
                        break;
                    }
                }
                list.add(saleNumber);
                list.add(totalSaleAmount);
            }
            list.add(saleNumberSum);
            list.add(totalSaleAmountSum);
            list.add("");

            dataList.add(list);
        }

        //处理最后行的合计
        List<Object> list = new ArrayList<>();
        list.add("合计");
        list.add("--");

        for (BigDecimal unitPrice : unitPriceList) {
            Integer saleNumberTotal= 0;
            BigDecimal totalSaleAmountTotal = new BigDecimal(0.0);

            for (SwCkInternetTicketEquipmentLineExcelDTO station : stationList){
                for(SwCkInternetTicketEquipmentLineExcelDTO dto : records){
                    if(unitPrice.equals(dto.getUnitPrice()) && station.getStationName().equals(dto.getStationName()) && station.getLineName().equals(dto.getLineName())){
                        saleNumberTotal +=  dto.getSaleNumber();
                        totalSaleAmountTotal = totalSaleAmountTotal.add(dto.getTotalSaleAmount());
                        break;
                    }
                }
            }

            list.add(saleNumberTotal);
            list.add(totalSaleAmountTotal);
        }
        //总计
        Map<String,Object> map = getSumTotal(dataList);
        list.add(map.get("saleNumberSumTotal"));
        list.add(map.get("totalSaleAmountSumTotal"));
        list.add("--");
        dataList.add(list);
        return dataList;
    }
    /**
     * 计算总计
     * @param dataList
     * @return
     */
    private Map<String,Object> getSumTotal( List<List<Object>> dataList){
        Map<String,Object> map = new HashMap<>();
        Integer saleNumberSumTotal = 0;
        BigDecimal totalSaleAmountSumTotal = new BigDecimal("0.0");

        for (List<Object> list : dataList) {
            saleNumberSumTotal += (Integer) list.get(list.size() - 3);
            totalSaleAmountSumTotal = totalSaleAmountSumTotal.add((BigDecimal)list.get(list.size() - 2));
        }
        map.put("saleNumberSumTotal",saleNumberSumTotal);
        map.put("totalSaleAmountSumTotal",totalSaleAmountSumTotal);
        return map;
    }

    /**
     * 导出(分日期)
     * @param
     * @return
     * @throws IOException
     */
    @Override
    public void exportExcelGroupDate(String startDate, String endDate, HttpServletResponse response) {
        List<SwCkInternetTicketEquipmentDateExcelDTO> records  = listGroupDate(startDate,endDate);
        InputStream excelTemplateIs = null;
        try {
            response.reset(); // 非常重要
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            final String fileName = URLEncoder.encode("互联网售票机(分日期)数据", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + System.currentTimeMillis() + ".xlsx");

            // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
            // {} 代表普通变量 {.} 代表是list的变量

            excelTemplateIs = this.getClass().getResourceAsStream("/static/excel/template/export/SwAuInternetTicketEquipmentDateExcelTemplate.xlsx");

            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerConverter(new LocalDateTimeConverter()).registerConverter(new LocalDateConverter()).withTemplate(excelTemplateIs).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("互联网售票机(分日期)数据").build();
            // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行，然后下面的数据往后移动。默认 是false，会直接使用下一行，如果没有则创建。
            // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了，所以慎用
            // 简单的说 如果你的模板有list,且list不是最后一行，下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
            // 如果数据量大 list不是最后一行 参照另一个
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(records, fillConfig, writeSheet);

            Map<String, Object> map = new HashMap<>();
            map.put("currMonth", DateUtils.format(new Date(),"yyyy-MM"));
            map.putAll(getSum(records));
            excelWriter.fill(map, writeSheet);
            excelWriter.finish();

        } catch (Exception e) {
            e.printStackTrace();
            log.error("导出互联网售票机(分日期)数据错误");
        } finally {
            if(excelTemplateIs != null){
                try {
                    excelTemplateIs.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }

            }
        }
    }

    private  List<SwCkInternetTicketEquipmentDateExcelDTO> listGroupDate(String startDate, String endDate) {
        return this.baseMapper.listGroupDate(startDate,endDate);
    }

    /**
     * 计算合计
     * @param records
     * @return
     */
    private Map<String,Object> getSum( List<SwCkInternetTicketEquipmentDateExcelDTO> records){
        Map<String,Object> map = new HashMap<>();
        Integer totalNumberSalesSum = 0;
        BigDecimal subtotalTotalSum = new BigDecimal("0.0");

        for (SwCkInternetTicketEquipmentDateExcelDTO dto : records) {
            totalNumberSalesSum += dto.getTotalNumberSales();
            subtotalTotalSum = subtotalTotalSum.add(dto.getConfirmAmount());
        }
        map.put("totalNumberSalesSum",totalNumberSalesSum);
        map.put("subtotalTotalSum",subtotalTotalSum);
        return map;
    }

}
